package com.tengju.payment.domain.model.transfer;

import com.tengju.payment.domain.model.BusinessType;
import com.tengju.payment.domain.model.ChannelType;
import com.tengju.payment.domain.model.HandleContext;
import com.tengju.payment.domain.model.TradeStatus;
import com.tengju.payment.domain.model.channel.Channel;
import com.tengju.payment.domain.model.channel.ChannelId;
import com.tengju.payment.domain.shard.Amount;
import com.tengju.payment.domain.shard.DomainException;
import com.tengju.payment.domain.shard.DomainExceptionCode;
import lombok.Value;
import lombok.experimental.NonFinal;

import java.time.LocalDateTime;
import java.util.Optional;


/**
 * 代付转账模型
 */
@Value
public class Transfer {

    /**
     * 转账唯一标识
     */
    TransferId transferId;

    /**
     * 业务类型
     */
    BusinessType businessType;

    /**
     * 交易渠道编号
     */
    @NonFinal
    ChannelId channelId;

    /**
     * 交易渠道类型
     */
    @NonFinal
    ChannelType channelType;

    /**1
     * 交易状态
     */
    @NonFinal
    TradeStatus tradeStatus;


    /**
     * 业务流水号
     */
    BusinessNo businessNo;

    /**
     * 本地交易流水号
     */
    @NonFinal
    String tradeNo;

    /**
     * 渠道返回流水号
     */
    @NonFinal
    String outTradeNo;

    /**
     * 交易金额
     */
    Amount tradeAmount;

    /**
     * 调用渠道时间
     */
    @NonFinal
    LocalDateTime requestTime;

    /**
     * 交易完成时间
     */
    @NonFinal
    LocalDateTime completeTime;

    /**
     * 交易请求关键信息
     */
    HandleContext requestInfo;

    /**
     * 返回关键信息
     */
    HandleContext responseInfo;

    /**
     * 扩展信息
     */
    @NonFinal
    TransferExtra extra;

    /**
     * 转账记录提交渠道
     */
    public void submitChannel(Channel channel) {
        if (this.channelId == null) {
            this.channelId = channel.getChannelId();
            this.channelType = channel.getChannelType();
        } else {

            throw DomainException.error(DomainExceptionCode.CHANNEL_ALREADY_BIND, this.businessNo);

        }
        this.tradeNo = TransferFactory.createLocalTradeNo(channel, this.businessNo, this.transferId);
        this.requestTime = LocalDateTime.now();
    }

    /**
     * 根据渠道返回信息更新结果
     */
    public void handleChannelResponse(TradeStatus tradeStatus, LocalDateTime channelSuccessTime, String channelRespMessage) {
        changeStatusTo(tradeStatus);
        if (this.tradeStatus.isComplete()) {
            this.completeTime = LocalDateTime.now();

            if (this.getExtra() == null) {
                this.extra = new TransferExtra();
            }
            this.extra.setChannelSuccessTime(channelSuccessTime);
            this.extra.setChannelRespMessage(channelRespMessage);
        }
    }

    private void changeStatusTo(TradeStatus targetStatus) {
        if (tradeStatus.canChangeTo(targetStatus)) {
            tradeStatus = targetStatus;
        } else {
            throw DomainException.error(DomainExceptionCode.TRADE_STATUS_CHANGE_FAIL, tradeStatus, targetStatus);
        }
    }

    public String accountName() {
        return Optional.ofNullable(extra)
                .map(TransferExtra::getAccountName).orElse("");
    }

    public String depositoryId() {
        return Optional.ofNullable(extra)
                .map(TransferExtra::getDepositoryId).orElse("");
    }


    public String bankName() {
        return Optional.ofNullable(extra)
                .map(TransferExtra::getBankSettleName).orElse("");
    }



    public String cardNo() {
        return Optional.ofNullable(extra)
                .map(TransferExtra::getAccountNo).orElse("");
    }

    public CertificationTypeEnum certificationType() {
        return Optional.ofNullable(extra)
                .map(TransferExtra::getCertificationType)
                .map(CertificationTypeEnum::parseByCode).orElse(null);
    }
}
